diff options
| author | Bertrand Yuan <bert.yuan@outlook.com> | 2025-12-16 00:12:49 +0800 |
|---|---|---|
| committer | Bertrand Yuan <bert.yuan@outlook.com> | 2025-12-16 00:12:49 +0800 |
| commit | 02ae938c238c9d18448d17a8ec92c0edd8c17463 (patch) | |
| tree | dcd6a30505adb52522b20af2c0ac27f713403f10 /src/app/(main)/(home)/posts/[slug]/page.client.tsx | |
| parent | 48b07bc308a35734a6a7a305c8fdccbfa47de7d8 (diff) | |
feat(back-end): introduce payload
Payload is the next.js Headless CMS and App Framework,
I would like to pick it up and modify it as it is MIT licensed.
Many features in Payload is not applicable for our project.
So, I modify it so that it is light and clear.
Diffstat (limited to 'src/app/(main)/(home)/posts/[slug]/page.client.tsx')
| -rw-r--r-- | src/app/(main)/(home)/posts/[slug]/page.client.tsx | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/app/(main)/(home)/posts/[slug]/page.client.tsx b/src/app/(main)/(home)/posts/[slug]/page.client.tsx new file mode 100644 index 0000000..7a97f56 --- /dev/null +++ b/src/app/(main)/(home)/posts/[slug]/page.client.tsx @@ -0,0 +1,57 @@ +'use client'; +import { + UploadIcon as ShareIcon, + type UploadIconHandle as ShareIconHandle, +} from '@/components/icons/animated/upload'; +import { Icons } from '@/components/icons/icons'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; +import { Comments } from '@fuma-comment/react'; +import { redirect } from 'next/navigation'; +import { useRef } from 'react'; +import { toast } from 'sonner'; +import { useCopyToClipboard } from 'usehooks-ts'; + +export function Share({ url }: { url: string }): React.ReactElement { + const iconRef = useRef<ShareIconHandle>(null); + const [_, copyToClipboard] = useCopyToClipboard(); + + const onClick = async (): Promise<void> => { + await copyToClipboard(`${window.location.origin}${url}`); + toast.success('Copied to clipboard!', { + icon: <Icons.copied className='size-4' />, + description: 'The post link has been copied to your clipboard.', + }); + }; + + return ( + <Button + className={cn('group gap-2')} + variant={'secondary'} + onClick={onClick} + onMouseEnter={() => iconRef.current?.startAnimation?.()} + onMouseLeave={() => iconRef.current?.stopAnimation?.()} + > + <ShareIcon className='size-4 hover:bg-transparent' ref={iconRef} /> + Share Post + </Button> + ); +} + +export function PostComments({ + slug, + className, +}: { slug: string; className?: string }) { + return ( + <Comments + page={slug} + className={cn('w-full', className)} + auth={{ + type: 'api', + signIn: () => { + redirect('/login'); + }, + }} + /> + ); +} |
